package cn.wanda.bi.sunshine.platform.server.utils.exception;

import cn.wanda.bi.sunshine.platform.server.SunshineCode;
import cn.wanda.bi.sunshine.platform.server.controller.response.common.SimpleResponse;

import com.fasterxml.jackson.core.JsonGenerator;
import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.view.json.MappingJackson2JsonView;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by wangfupeng1
 */
@Component
@ControllerAdvice
public class SunshineExceptionHandler {

    private static final Logger logger = LoggerFactory.getLogger(SunshineExceptionHandler.class);

    @ResponseBody
    @ExceptionHandler(SunshineException.class)
    public ModelAndView sailExceptionHandler(RuntimeException e, HttpServletResponse response) {

        ModelAndView mav = new ModelAndView();
        if (e instanceof SunshineException) {
            int status = ((SunshineException) e).getStatus();
            Jackson2JsonView view = new Jackson2JsonView();
            Map<String, Object> attributes = new HashMap<>();
            attributes.put("status", status);
            attributes.put("message", e.getMessage());
            attributes.put("data", null);
            attributes.put("more info", "");
            view.setAttributesMap(attributes);
            view.setPrettyPrint(true);
            mav.setView(view);
            logger.error("【Error】", e);
        }
        return mav;
    }

    @ResponseBody
    @ExceptionHandler(ClientException.class)
    public ModelAndView clientExceptionHandler(RuntimeException e, HttpServletResponse response) {

        ModelAndView mav = new ModelAndView();
        if (e instanceof ClientException) {
            int status = ((ClientException) e).getStatus();
            Jackson2JsonView view = new Jackson2JsonView();
            Map<String, Object> attributes = new HashMap<>();
            attributes.put("status", status);
            attributes.put("message", e.getMessage());
            attributes.put("data", null);
            attributes.put("more info", "");
            view.setAttributesMap(attributes);
            view.setPrettyPrint(true);
            mav.setView(view);
            logger.error("【Error】", e);
        }
        return mav;
    }

    @ResponseBody
    @ExceptionHandler(BindException.class)
    public ModelAndView bindExceptionHandler(BindException e, HttpServletResponse response) {

        ModelAndView mav = new ModelAndView();
        Jackson2JsonView view = new Jackson2JsonView();
        Map<String, Object> attributes = new HashMap<>();
        attributes.put("status", SunshineCode.PARAM_ERROR);
        attributes.put("message", "参数有误");
        attributes.put("data", null);
        List<ObjectError> errors = e.getBindingResult().getAllErrors();
        StringBuilder moreInfo = new StringBuilder();
        if (CollectionUtils.isNotEmpty(errors)) {
            errors.stream().filter(error -> error instanceof FieldError).forEach(error ->
                    moreInfo.append(((FieldError) error).getField())
                            .append(":").append(error.getDefaultMessage())
                            .append(";"));
        }
        attributes.put("more info", moreInfo.toString());
        view.setAttributesMap(attributes);
        view.setPrettyPrint(true);
        mav.setView(view);
        logger.error("【Error】", e);
        return mav;
    }

    @ResponseBody
    @ExceptionHandler(Exception.class)
    public ModelAndView exceptionHandler(Exception e, HttpServletResponse response) {
        ModelAndView mav = new ModelAndView();
        Jackson2JsonView view = new Jackson2JsonView();
        Map<String, Object> attributes = new HashMap<>();
        if (e instanceof Exception) {
            attributes.put("status", SunshineCode.UNKNOWN);
           // attributes.put("message", "未知错误");
            attributes.put("message", temp(e)/*.substring(0, 190)*/);
          //  attributes.put("message", e.toString());
            attributes.put("data", null);
            attributes.put("more info", "");
            view.setAttributesMap(attributes);
            view.setPrettyPrint(true);
            mav.setView(view);
            logger.error("【Error】", e);
        }
        return mav;
    }

    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseBody
    public SimpleResponse handleMethodArgumentNotValidException(
            MethodArgumentNotValidException ex) {
        BindingResult bindingResult = ex.getBindingResult();
        String errorMesssage = "";
        for (FieldError fieldError : bindingResult.getFieldErrors()) {
            errorMesssage += fieldError.getField() + fieldError.getDefaultMessage() + ", ";
        }

        SimpleResponse response = new SimpleResponse();
        response.setStatus(SunshineCode.PARAM_ERROR);
        response.setMessage(errorMesssage);
        return response;
    }

    @ExceptionHandler(MethodArgumentTypeMismatchException.class)
    @ResponseBody
    public SimpleResponse handleMethodArgumentTypeMismatchException(
            MethodArgumentTypeMismatchException ex) {
        SimpleResponse response = new SimpleResponse();
        response.setStatus(SunshineCode.PARAM_ERROR);
        response.setMessage(ex.getName()
                + " needs " + ex.getRequiredType() + ", got value: " + ex.getValue());

        return response;
    }

    @ExceptionHandler(MissingServletRequestParameterException.class)
    @ResponseBody
    public SimpleResponse handleMissingServletRequestParameterException(
            MissingServletRequestParameterException ex) {
        SimpleResponse response = new SimpleResponse();
        response.setStatus(SunshineCode.PARAM_ERROR);
        response.setMessage(ex.getParameterName() + " required but missing");
        return response;
    }

    private String temp(Exception e){
        String aaa=e.getMessage();
        for (StackTraceElement element : e.getStackTrace()) {
            aaa+= element.toString();
        }

        return aaa;
    }

    class Jackson2JsonView extends MappingJackson2JsonView {
        @Override
        protected void writePrefix(JsonGenerator generator, Object object) throws IOException {
        }

        @Override
        protected void writeSuffix(JsonGenerator generator, Object object) throws IOException {
        }
    }

}